package it.sisiper.mysight;

import it.sisiper.mysight.MySight.Previewer;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.net.InetAddress;
import java.net.Socket;
import java.util.Timer;
import java.util.TimerTask;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.os.AsyncTask;

/**
 * Thread created each time the streaming tries to start, destroyed on connection hangs or user wishing to stop the stream. 
 * 
 * @author Federico Lancerin 1057505
 *
 */

public class NetworkAndTime extends Thread {

	private long intervalBetweenAcquisitions = 1000;

	private int orientation;
	private boolean acquireAndSend;
	private Timer timer;

	private int sendingStatus;
	private final int FREE = 0;
	private final int SENDING = 1;

	private String serverAddress;
	private Previewer prev;

	private Socket socket;
	private OutputStream out;
	private ByteArrayOutputStream fout;
	private Bitmap bitmapImg;
	private Bitmap rotatedImg;
	private InputStream in;
	private String str;
	private String ackStr;
	private boolean connected;
	
	Matrix matrix90 = new Matrix();
	Matrix matrix180 = new Matrix();

	public NetworkAndTime(Previewer previ) {
		prev = previ;
		connected = false;
		acquireAndSend = false;
		timer = new Timer();
		matrix90.setRotate(90f);
		matrix180.setRotate(180f);
	}

	public void setServerAddress(String serverAddr) {
		serverAddress = serverAddr;
	}

	public void setAcquisition(boolean acquire) {
		acquireAndSend = acquire;
	}

	public void setOrientation(int orient) {
		orientation = orient;
	}

	public void setDelay(int delay) {
		intervalBetweenAcquisitions = (delay * 1000);
	}

	public boolean isConnected() {
		return connected;
	}

	public void disconnectFromServer() {
		if (connected) {
			if (out != null)
				try {
					out.close();
				} catch (IOException e1) {
					e1.printStackTrace();
				}
			if ((socket != null) && socket.isConnected())
				try {
					socket.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
			if (timer != null)
				timer.cancel();
			connected = false;
		}
	}

	public void run() {
		if (serverAddress != null) {
			try {
				System.out.println("trying to connect");
				socket = new Socket(InetAddress.getByName(serverAddress), 8090);
				socket.setSoTimeout(30000);
				connected = true;
				sendingStatus = FREE;
				System.out.println("connected!");
				timer.schedule(clock, 0, intervalBetweenAcquisitions);
			} catch (IOException e) {
				e.printStackTrace();
				System.out.println("not connected!");
				connected = false;
			}
		} else
			System.out.println("ServerAddress = null");
	}

	public void sendPhoto(byte[] data) {
		try {
			out = socket.getOutputStream();			
			if (orientation == -1) {
				YuvImage yuvImage = new YuvImage(data, ImageFormat.NV21, 640, 480, null);
				fout = new ByteArrayOutputStream();
				yuvImage.compressToJpeg(new Rect(0, 0, 640, 480), 50, fout);
				byte[] newData = fout.toByteArray();
				str = "image " + 640 + "x" + 480 + " " + (newData.length) + "\n";
				byte[] strB = str.getBytes();			
				out.write(strB);
				out.flush();
				out.write(newData);
				out.flush();
			} else {
				fout = new ByteArrayOutputStream();
				YuvImage image = new YuvImage(data, ImageFormat.NV21, 640, 480,	null);
				image.compressToJpeg(new Rect(0, 0, 640, 480), 50, fout);
				byte[] newData = fout.toByteArray();
				bitmapImg = BitmapFactory.decodeByteArray(newData, 0, newData.length);
				byte[] newerData = null;
				if (orientation == 0) {
					rotatedImg = bitmapImg.createBitmap(bitmapImg, 0, 0, bitmapImg.getWidth(), bitmapImg.getHeight(), matrix90, false);
					fout = new ByteArrayOutputStream();
					rotatedImg.compress(Bitmap.CompressFormat.JPEG, 60, fout);
					newerData = fout.toByteArray();
					str = "image " + 480 + "x" + 640 + " " + (newerData.length) + "\n";					
				}
				if (orientation == 1) {
					rotatedImg = bitmapImg.createBitmap(bitmapImg, 0, 0, bitmapImg.getWidth(), bitmapImg.getHeight(), matrix180, false);
					fout = new ByteArrayOutputStream();
					rotatedImg.compress(Bitmap.CompressFormat.JPEG, 60, fout);
					newerData = fout.toByteArray();
					str = "image " + 640 + "x" + 480 + " " + (newerData.length) + "\n";
				}
				byte[] strB = str.getBytes();
				out.write(strB);
				out.flush();
				out.write(newerData);
				out.flush();
			}
			System.out.println("Pic sent!");
			in = socket.getInputStream();
			new waitForString().execute(in);
		} catch (IOException e) {
			System.out.println("Socket Exception, connected = false");
			connected = false;
			e.printStackTrace();
		}
	}

	private TimerTask clock = new TimerTask() {
		@Override
		public void run() {
			if (acquireAndSend) {
				if (sendingStatus == FREE) {
					sendingStatus = SENDING;
					prev.takePic();
				}
			}
		}
	};

	private class waitForString extends AsyncTask<InputStream, Void, String> {
		protected String doInBackground(InputStream... in) {
			try {
				InputStream input = (InputStream) in[0];
				ackStr = receiveString(input);
			} catch (IOException e) {
				connected = false;
				e.printStackTrace();
			}
			return ackStr;
		}
		protected void onPostExecute(String ack) {
	        System.out.println("received : " + ack);
			sendingStatus = FREE;
	    }
	}	
	
	private String receiveString(InputStream in) throws IOException {

		byte[] reading = new byte[100];
		int count = 0;
		while (true) {
			if (count == 100)
				throw new IOException();
			int read = in.read();
			if ((read == (int) '\n') || (read < 0))
				break;
			reading[count++] = (byte) read;
		}
		if (count == 0)
			return null;
		return new String(reading, 0, count);
	}

}
